﻿#ifndef __INC_QG_D11_RES_H__
#define __INC_QG_D11_RES_H__

#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4200)	// 비표준 확장이 사용됨 : 구조체/공용 구조체의 배열 크기가 0입니다.
#endif

#include "qg/qgimage.h"
#include "qg_subtex.h"

//////////////////////////////////////////////////////////////////////////
// 텍스쳐
class D11Texture : public qgTexture
{
	KCH_SUBCLASS(D11Texture, qgTexture);
	KCH_FRIEND(D11Device);

protected:
	qgImage*			_img_rsw;
	qgImage*			_img_mip;

	DXGI_FORMAT			_dev_fmt;
	DXGI_SAMPLE_DESC	_dev_slp;

	ID3D11Resource*		_dev_tex;

protected:
	D11Texture() throw();
	~D11Texture() throw();

public:
	K_OVR bool EnterMap(qgTextureMap* map, kint flag, kint mips, qgTextureFace face);
	K_OVR bool LeaveMap();

	ID3D11ShaderResourceView* GetShaderResourceView() { return (ID3D11ShaderResourceView*)GetDescription(); }

protected:
	bool _InitImage(const char* name, qgImage* img, kint mips, kint flags, D11Device* dev);
	bool _InitProperty(qgTextureType type, const char* name, kint width, kint height, kint depth, kint mips, kint flags, qgColorFormat fmt, D11Device* dev);
	bool _CreateInternal(ID3D11ShaderResourceView** psrv, ID3D11Resource** pres, D3D11_SUBRESOURCE_DATA* subd, D11Device* dev);
	bool _CreateTexture(qgImage* img, D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 모션 텍스쳐, 클래스의 이중 상속...이 있다
class D11TextureMotion : public D11Texture, public qgSubTextureMotion
{
	KCH_SUBCLASS(D11TextureMotion, D11Texture);
	KCH_FRIEND(D11Device);

private:
	D11TextureMotion() throw();
	~D11TextureMotion() throw();

public:
	K_OVR qgITextureMotion* GetMotion();

	// qgITextureMotion
	K_OVR bool MotionUpdate(float adv);

private:
	bool _CreateMotion(const char* filename, kint flags, D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 뎁스 버퍼
class D11DepthBuffer : public qgDepthBuffer
{
	KCH_SUBCLASS(D11DepthBuffer, qgDepthBuffer);
	KCH_FRIEND(D11Device);

protected:
	D11DepthBuffer() throw();
	~D11DepthBuffer() throw();

private:
	bool _Create(kuint width, kuint height, D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 오프 텍스쳐
class D11TextureOff : public D11Texture, public qgITextureOff
{
	KCH_SUBCLASS(D11TextureOff, D11Texture);
	KCH_FRIEND(D11Device);

private:
	ID3D11RenderTargetView*		_rtv;
	D11DepthBuffer*				_db;

private:
	D11TextureOff() throw();
	~D11TextureOff() throw();

public:
	K_OVR qgITextureOff* GetOff();

	// qgITextureOff
	K_OVR bool EnterOff(kint clearance, const tpl::ColorValue& color);
	K_OVR bool LeaveOff();

private:
	bool _CreateOff(D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 래스터라이저
class D11Rasz : public qgRasz
{
	KCH_SUBCLASS(D11Rasz, qgRasz);
	KCH_FRIEND(D11Device);

private:
	ID3D11DepthStencilState*	_dss;

private:
	D11Rasz() throw();
	~D11Rasz() throw();

public:
	ID3D11RasterizerState* GetRasterizerState() { return (ID3D11RasterizerState*)GetDescription(); }
	ID3D11DepthStencilState* GetDepthStencilState() { return _dss; }

private:
	bool _CreateRasz(const qgRaszData& data, D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 블렌드
class D11Blnd : public qgBlnd
{
	KCH_SUBCLASS(D11Blnd, qgBlnd);
	KCH_FRIEND(D11Device);

private:
	D11Blnd() throw();
	~D11Blnd() throw();

public:
	ID3D11BlendState* GetBlendState() { return (ID3D11BlendState*)GetDescription(); }

private:
	bool _CreateBlnd(const qgBlndData& data, D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 샘플러
class D11Splr : public qgSplr
{
	KCH_SUBCLASS(D11Splr, qgSplr);
	KCH_FRIEND(D11Device);

private:
	D11Splr() throw();
	~D11Splr() throw();

public:
	ID3D11SamplerState* GetSamplerState() { return (ID3D11SamplerState*)GetDescription(); }

private:
	bool _CreateSplr(const qgSplrData& data, D11Device* dev);
};


//////////////////////////////////////////////////////////////////////////
// 세이더
class D11Shader : public qgShader
{
	KCH_SUBCLASS(D11Shader, qgShader);
	KT_DECL_TYPE_INIT(D11Shader);
	KCH_FRIEND(D11Device);
	KCH_FRIEND(D11Layout);
	KCH_INTERN(ReadInclude);

public:
	struct MapBuffer : tpl::MemBase
	{
		ID3D11Buffer*				buf;
		D3D11_SHADER_BUFFER_DESC	desc;
		tpl::Array<qgShaderVar>		vars;	// 고정 길이
	};

	struct BufferData : public tpl::MemBase
	{
		kint						ref;
		ID3D11ShaderReflection*		sr;
		tpl::Array<MapBuffer*>		maps;	// 고정 길이
		tpl::Array<kbyte>			keep;	// 고정 길이
	};

private:
	ID3D11PixelShader*		_ps;
	ID3D11VertexShader*		_vs;

	BufferData*				_dps;
	BufferData*				_dvs;

	//ID3D11GeometryShader*	_gs; <- 나중에 하자...
	//ID3D11InputLayout*	_il; <- _node_desc로 대체한다

	bool					_linked;

private:
	D11Shader() throw();
	~D11Shader() throw();

public:
	K_OVR bool BindFile(qgShaderType type, const char* filename, kint flags) throw();
	K_OVR bool BindData(qgShaderType type, kconstpointer data, kint size, kint flags) throw();
	K_OVR bool BindShader(qgShaderType type, const char* name) throw();
	K_OVR bool Link();

	K_OVR qgShaderVar* GetVars(kint stage, kint* count);

private:
	bool _InternalBindData(qgShaderType type, kconstpointer data, kint size, kint flags, const char* filename) throw();

	void _PrintError(ID3DBlob* errs, kint errcode, const char* target);
	bool _CreatePixelShader(kconstpointer data, kint size, D3D_SHADER_MACRO* mcs, ReadInclude& inc, DWORD dw, const char* filename) throw();
	bool _CreateVertexShader(kconstpointer data, kint size, D3D_SHADER_MACRO* mcs, ReadInclude& inc, DWORD dw, const char* filename) throw();
	BufferData* _AnalyzeData(qgShaderType type, kpointer data, ksize_t size, bool keep, bool parseinput);

	static D3D_SHADER_MACRO* _MakeDefinition(ConditionArray& conds);
	static DWORD _MakeFlags(kint v);
	static void _RemoveData(IUnknown** unk, BufferData** bd, bool reset);

	static kpointer _MatchAutoFunc(qgShaderVar& v);
	static void _InitAutoFunc();
	static qgShaderData _ShaderTypeToShaderData(const D3D11_SHADER_TYPE_DESC& std);

	void _ProcessMap(ID3D11DeviceContext* ctx) throw();
	UINT _UploadShader(BufferData* bd, ID3D11Buffer** bs, UINT maxbs, ID3D11DeviceContext* ctx) throw();
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif	// __INC_QG_D11_RES_H__
